/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com */

/*
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "text.h"

namespace tri {

std::map<std::string,tri::triFont*> TText::mFontList = std::map<std::string,tri::triFont*>();
std::map<std::string,int> TText::mFontReferences = std::map<std::string,int>();

TText::TText() :
    tri::TEntity(), mFontSize(10), mFont(NULL), mCharacterHeight(10),
            mReloadFont(true), prevFont(""), mFontName("times.TTF"),mText("") {
    setClipInsets(0,0,0,0);
    mTextBGColor.setValue(0,0,0,0);
}

TText::~TText() {
    TText::removeFontReference(getFontFullName());
}

int TText::getDimensions(std::string t,float &width, float &height){
    try {
        loadFont();
    } catch(tri::TriException()) {
        width =0;
        height =0;
        return -1;
    } catch(...) {
        width = 0;
        height = 0; 
        return -1; 
    }
    
    if (mFont!=NULL) { 
        mFont->getDimensions(t,mCharacterHeight,width,height);
        return 0;
    }
    
    width =0;
    height =0;
    return -1;

}

int TText::getDimensions(float &width, float &height){
    try {
        loadFont();
    } catch(tri::TriException()) {
        width =0;
        height =0;
        return -1;
    } catch(...) {
        width = 0;
        height = 0;
        return -1;
    }
    
    if (mFont!=NULL) {
        mFont->getDimensions(mLines,mCharacterHeight,width,height);
        return 0;
    }
    
    width =0;
    height =0;
    return -1;
}

int TText::getCharBitmapDimensions(char c,int &width, int& height){
    try {
        loadFont();
    } catch(tri::TriException()) {
        width =0;
        height =0;
        return -1;
    } catch(...) {
        width = 0; 
        height = 0;
        return -1;
    }
    
    if (mFont!=NULL) {
        mFont->getCharBitmapDimensions(c,width,height);
        return 0;
    }
    
    width =0;
    height =0;
    return -1; 

}

void TText::setClipInsets(float inset_left, float inset_top,
        float inset_right, float inset_bottom) {
    mClipInsets[0]=inset_left;
    mClipInsets[1]=inset_top;
    mClipInsets[2]=inset_right;
    mClipInsets[3]=inset_bottom;
//    requestRepaint();
}


void TText::loadFont(){
    std::string fontName = getFontFullName();
    if (mReloadFont && fontName != "") {
        if (fontExists(fontName)) {
            mFont = TText::mFontList[fontName];
            TText::mFontReferences[fontName]++;
        } else {
        	//std::cout<<"Creating "<<fontName<<std::endl;
            TText::mFontList[fontName] = tri::triFont::getFont(mFontName, mFontSize);
            TText::mFontReferences[fontName] = 0;
            mFont = mFontList[fontName];
            TText::mFontReferences[fontName]++;
        }
        TText::removeFontReference(prevFont);
        mReloadFont = false;			
    }
}

bool TText::fontExists(std::string font){
	std::map<std::string,tri::triFont*>::iterator it;
	for ( it=TText::mFontList.begin() ; it != TText::mFontList.end(); it++ ){
		if(font==(*it).first){
			return true;
		}
	}
	
	return false;
}

void TText::display() {
    try {
        loadFont();
    } catch(tri::TriException()) {
        return;
    } catch(...) {
        return;

    } 

    
    if (mFont!=NULL) { 
        float w1,h1;
        float w2,h2;
        float w ,h; 
        getDimensions("H",w1,h1);
        getDimensions(w,h);
        
        mTextBGColor.apply();
        glBindTexture(GL_TEXTURE_2D,0);
        glBegin(GL_QUADS);
        glVertex2f(0, h1);
        glVertex2f(0, -getGlyphTopMargin());
        glVertex2f(w, -getGlyphTopMargin());
        glVertex2f(w, h1);
        glEnd();
         
        //std::cout<<"Printing "<<std::endl;
        mFont->printLines(mLines,0.0, 0.0, mCharacterHeight,
                mClipInsets[0],mClipInsets[1],mClipInsets[2],mClipInsets[3],&mTextColor);
        //std::cout<<"Done "<<std::endl;
    }
}

float TText::getGlyphTopMargin(){
    try {
        loadFont();
    } catch(tri::TriException()) {
        return 0;
    } catch(...) {
        return 0;
    }
    
    if (mFont!=NULL) {
        return mFont->getGlyphTopMargin(mCharacterHeight);
    }
    
    return 0;
    
}

void TText::removeFontReference(std::string f){
    if(TText::mFontReferences.count(f)>0){
        mFontReferences[f]--;
        if (mFontReferences[f] == 0){
        	//std::cout<<"Deleting Font... "<<f<<std::endl;
            delete TText::mFontList[f];
            TText::mFontList.erase(f);
            TText::mFontReferences.erase(f);
        }
    }
}

void TText::setFontSize(int s) {
    if (s!=mFontSize && s>0) {
        prevFont = getFontFullName();
        mFontSize = s;
        mReloadFont = true;
    }
//    requestRepaint();
}

void TText::setCharacterHeight(float h) {
    mCharacterHeight = h;
}

float TText::getCharacterHeight(){
	return mCharacterHeight;
}


void TText::setFont(std::string font) {
	if (font.compare("")!=0){
	    if (tri::utils::toUpper(font).compare(tri::utils::toUpper(mFontName))!=0) {
	    	//std::cout<<"Text::SetFont "<<font<<" "<<mFontName<<std::endl;
	        prevFont = getFontFullName();
	        mFontName = font;
	        mReloadFont = true;
//	        requestRepaint();
	    }
	}
}

void TText::setTextColor(int r, int g, int b, int a) {
    mTextColor.setValue(r, g, b, a);
}

void TText::setTextTargetColor(int r, int g, int b, int a,float t){
	mTextColor.setTargetValue(r, g, b, a, t);
}

void TText::setTextBackGroundColor(int r, int g, int b, int a){
    mTextBGColor.setValue(r, g, b, a);
}

std::string TText::getFontFullName() {
    return mFontName+tri::utils::int2String(mFontSize, 10);
}

void TText::setText(const char* fmt,...){
	char text[1024]; // Holds Our String
    va_list ap; // Pointer To List Of Arguments

    if (fmt == NULL) { // If There's No Text
        return;
    } else {
        
        va_start(ap, fmt);
        // Parses The String For Variables
        vsprintf(text, fmt, ap); // And Converts Symbols To Actual Numbers
        va_end(ap);
        // Results Are Stored In Text
    }
    mText = std::string(text);
	mLines.clear();
	std::string line;
	for (unsigned int i =0;i<mText.size();i++){ 
		char c = mText.c_str()[i];
		if(c=='\n'){
			mLines.push_back(line);
			line ="";
		}else{
			line.append(1,c);
			if(i==mText.size()-1){
				mLines.push_back(line);
			}
		}
	}
	
//    requestRepaint();
    
}

void TText::setText(std::string text){
	setText(text.c_str());
}

std::string TText::getText(){
    return mText;
}

}